package cn.lg.soar.flow.biz.listener;

import cn.lg.soar.common.util.AssertUtil;
import cn.lg.soar.common.util.data.DataUtil;
import cn.lg.soar.flow.api.enums.ApproverMissingEnum;
import cn.lg.soar.flow.api.enums.ApproverTypeEnum;
import cn.lg.soar.flow.api.model.node.ApprovalNode;
import cn.lg.soar.flow.api.model.node.Assignee;
import cn.lg.soar.flow.api.utils.ProcessUtils;
import cn.lg.soar.flow.biz.entity.SoarApprover;
import cn.lg.soar.flow.biz.mapper.SoarApproverMapper;
import cn.lg.soar.flow.biz.service.SoarProcessVersionService;
import cn.lg.soar.system.api.model.OrgDTO;
import cn.lg.soar.system.api.service.IOrgApi;
import cn.lg.soar.system.api.service.IPostApi;
import cn.lg.soar.system.api.service.IUserApi;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import org.flowable.engine.delegate.DelegateExecution;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.stream.Collectors;

/**
 * @author Administrator
 */
@Component("taskApproverHandler")
public class TaskApproverHandler {

    @Autowired
    private SoarProcessVersionService soarProcessVersionService;
    @Autowired
    private SoarApproverMapper approverMapper;
    @Autowired
    private IUserApi userApi;
    @Autowired
    private IOrgApi orgApi;
    @Autowired
    private IPostApi postApi;

    /**
     * 审批人，单实例节点使用
     * @param execution
     * @return
     */
    public String approverStr(DelegateExecution execution) {
        Set<String> userList = getApproverList(execution);
        return String.join(",", userList);
    }

    /**
     * 审批人，多实例节点使用
     * @param execution
     * @return
     */
    public List<String> approverList(DelegateExecution execution) {
        return getApproverList(execution).stream().toList();
    }

    private Set<String> getApproverList(DelegateExecution execution) {
        String processDefinitionId = execution.getProcessDefinitionId();
        String processInstanceId = execution.getProcessInstanceId();
        String taskKey = execution.getCurrentActivityId();
        Map<String, Object> variables = execution.getVariables();

        Map<String, ApprovalNode> nodeMap = soarProcessVersionService.getNodeMap(processDefinitionId);
        ApprovalNode node = nodeMap.get(taskKey);

        List<Assignee> assignees = node.getAssignees();
        Map<ApproverTypeEnum, List<Assignee>> group = assignees.stream().collect(Collectors.groupingBy(Assignee::getType));

        Set<String> userList = new HashSet<>();
        group.forEach((type, list) -> {
            switch (type) {
                case SPECIFIED_USER -> {
                    userList.addAll(
                            list.stream()
                                    .flatMap(x -> x.getIds().stream())
                                    .map(ProcessUtils::toUserApproval)
                                    .toList()
                    );
                }
                case SPECIFIED_POST -> {
                    userList.addAll(
                            list.stream()
                                    .flatMap(x -> x.getIds().stream())
                                    .map(ProcessUtils::toPostApproval)
                                    .collect(Collectors.toSet())
                    );
                }
                case SPECIFIED_ROLE -> {
                    Set<Long> roleIds = list.stream().map(Assignee::getLongValue).collect(Collectors.toSet());
                    List<Long> userIds = userApi.idsByRoleId(roleIds);
                    userList.addAll(
                            userIds.stream()
                                    .map(ProcessUtils::toUserApproval)
                                    .collect(Collectors.toSet())
                    );
                }
                case FORM_USER -> {
                    for (Assignee assignee : list) {
                        Object object = variables.get(assignee.getStrValue());
                        userList.addAll(
                                DataUtil.toLongs(object).stream()
                                        .map(ProcessUtils::toUserApproval)
                                        .toList()
                        );
                    }
                }
                case FORM_POST -> {
                    for (Assignee assignee : list) {
                        Object object = variables.get(assignee.getStrValue());
                        userList.addAll(
                                DataUtil.toLongs(object).stream()
                                        .map(ProcessUtils::toPostApproval)
                                        .collect(Collectors.toSet())
                        );
                    }
                }
                case INITIATOR_DEPT_ROLE -> {
                    // 流程发起人
                    Long initiator = getInitiator(variables);
                    if (initiator != null) {
                        for (Assignee x : list) {
                            OrgDTO org = orgApi.getUserOrg(initiator, x.getIntValue());
                            List<Long> userIds = userApi.idsByOrgAndRole(org.getId(), x.getLongValue());
                            userList.addAll(
                                    userIds.stream().map(ProcessUtils::toUserApproval).collect(Collectors.toSet())
                            );
                        }
                    }
                }
                case INITIATOR_DEPT_POST -> {
                    // 流程发起人
                    Long initiator = getInitiator(variables);
                    if (initiator != null) {
                        for (Assignee x : list) {
                            OrgDTO org = orgApi.getUserOrg(initiator, x.getIntValue());
                            List<Long> postIds = postApi.idsByOrgAndTag(org.getId(), x.getStrValue());
                            userList.addAll(
                                    postIds.stream().map(ProcessUtils::toPostApproval).collect(Collectors.toSet())
                            );
                        }
                    }
                }
                case BUSINESS_DEPT_ROLE -> {
                    // 业务所属部门
                    Long bizOrgId = getBizOrgId(variables);
                    if (bizOrgId != null) {
                        for (Assignee x : list) {
                            List<Long> userIds = userApi.idsByOrgAndRole(bizOrgId, x.getLongValue());
                            userList.addAll(
                                    userIds.stream().map(ProcessUtils::toUserApproval).collect(Collectors.toSet())
                            );
                        }
                    }
                }
                case BUSINESS_DEPT_POST -> {
                    // 业务所属部门
                    Long bizOrgId = getBizOrgId(variables);
                    if (bizOrgId != null) {
                        for (Assignee x : list) {
                            List<Long> postIds = postApi.idsByOrgAndTag(bizOrgId, x.getStrValue());
                            userList.addAll(
                                    postIds.stream().map(ProcessUtils::toPostApproval).collect(Collectors.toSet())
                            );
                        }
                    }
                }
                case INITIATOR_SELECT_USER, INITIATOR_SELECT_POST, APPROVER_SELECT_USER, APPROVER_SELECT_POST ->  {
                    // 自选审批人
                    List<SoarApprover> soarApprovers = approverMapper.selectList(
                            Wrappers.<SoarApprover>lambdaQuery()
                                    .select(SoarApprover::getApprovers)
                                    .eq(SoarApprover::getProcInstId, processInstanceId)
                                    .eq(SoarApprover::getNodeKey, taskKey)
                    );
                    for (SoarApprover soarApprover : soarApprovers) {
                        userList.addAll(soarApprover.getApprovers());
                    }
                }
            }
        });
        // 处理审批人为空的情况
        if (userList.isEmpty()) {
            ApproverMissingEnum missingAssignee = node.getMissingAssignee();
            AssertUtil.isTrue(missingAssignee != null, "未能找到下个节点审批人，无法提交");
            switch (missingAssignee) {
                case pass, reject -> userList.add(ProcessUtils.SYSTEM_APPROVAL);
                case defaultApprover -> userList.add(ProcessUtils.toUserApproval(node.getDefaultAssignee()));
                default -> AssertUtil.throwException("未能找到下个节点审批人，无法提交");
            }
        }
        return userList;
    }

    private Long getInitiator(Map<String, Object> variables) {
        Object initiator = variables.get("initiator");
        if (initiator == null) {
            return null;
        }
        return ProcessUtils.toUserId(initiator.toString());
    }

    private Long getBizOrgId(Map<String, Object> variables) {
        Object bizOrgId = variables.get("bizOrgId");
        if (bizOrgId == null) {
            return null;
        }
        if (bizOrgId instanceof Number) {
            return ((Number) bizOrgId).longValue();
        }
        return Long.parseLong(bizOrgId.toString());
    }


}